msg_tool\scripts\escude/
script.rs

1//! Escu:de Script File (.bin)
2use super::list::{EnumScr, EscudeBinList, ListData, NameT};
3use super::ops::base::CustomOps;
4use crate::ext::io::*;
5use crate::scripts::base::*;
6use crate::types::*;
7use crate::utils::encoding::{decode_to_string, encode_string};
8use crate::utils::struct_pack::StructPack;
9use anyhow::Result;
10use int_enum::IntEnum;
11use std::collections::{BTreeSet, HashMap};
12use std::ffi::CString;
13use std::io::{Read, Seek, SeekFrom};
14use unicode_segmentation::UnicodeSegmentation;
15
16#[derive(Debug)]
17/// Builder for Escu:de binary script files
18pub struct EscudeBinScriptBuilder {}
19
20impl EscudeBinScriptBuilder {
21    /// Creates a new instance of `EscudeBinScriptBuilder`
22    pub const fn new() -> Self {
23        EscudeBinScriptBuilder {}
24    }
25}
26
27impl ScriptBuilder for EscudeBinScriptBuilder {
28    fn default_encoding(&self) -> Encoding {
29        Encoding::Cp932
30    }
31
32    fn build_script(
33        &self,
34        data: Vec<u8>,
35        _filename: &str,
36        encoding: Encoding,
37        _archive_encoding: Encoding,
38        config: &ExtraConfig,
39        _archive: Option<&Box<dyn Script>>,
40    ) -> Result<Box<dyn Script>> {
41        Ok(Box::new(EscudeBinScript::new(data, encoding, config)?))
42    }
43
44    fn extensions(&self) -> &'static [&'static str] {
45        &["bin"]
46    }
47
48    fn script_type(&self) -> &'static ScriptType {
49        &ScriptType::Escude
50    }
51
52    fn is_this_format(&self, _filename: &str, buf: &[u8], buf_len: usize) -> Option<u8> {
53        if buf_len > 8 && buf.starts_with(b"ESCR1_00") {
54            return Some(255);
55        }
56        None
57    }
58}
59
60#[derive(Debug)]
61/// Escu:de binary script file
62pub struct EscudeBinScript {
63    vms: Vec<u8>,
64    unk1: u32,
65    strings: Vec<String>,
66    names: Option<HashMap<usize, String>>,
67}
68
69fn load_enum_script(
70    filename: &str,
71    encoding: Encoding,
72    config: &ExtraConfig,
73) -> Result<Vec<NameT>> {
74    let buf = crate::utils::files::read_file(filename)?;
75    let scr = EscudeBinList::new(buf, filename, encoding, config)?;
76    for scr in scr.entries {
77        match scr.data {
78            ListData::Scr(scr) => match scr {
79                EnumScr::Names(names) => return Ok(names),
80                _ => {}
81            },
82            _ => {}
83        }
84    }
85    Err(anyhow::anyhow!(
86        "Failed to find name table in Escude enum script",
87    ))
88}
89
90impl EscudeBinScript {
91    /// Creates a new `EscudeBinScript`
92    ///
93    /// * `data` - The reader to read the data from
94    /// * `encoding` - The encoding of the script
95    /// * `config` - Extra configuration options
96    pub fn new(data: Vec<u8>, encoding: Encoding, config: &ExtraConfig) -> Result<Self> {
97        let mut reader = MemReader::new(data);
98        let mut magic = [0u8; 8];
99        reader.read_exact(&mut magic)?;
100        if &magic != b"ESCR1_00" {
101            return Err(anyhow::anyhow!(
102                "Invalid Escude binary script magic: {:?}",
103                magic
104            ));
105        }
106        let string_count = reader.read_u32()?;
107        let mut offsets = Vec::with_capacity(string_count as usize);
108        for _ in 0..string_count {
109            offsets.push(reader.read_u32()?);
110        }
111        let vm_count = reader.read_u32()?;
112        let mut vms = Vec::with_capacity(vm_count as usize);
113        vms.resize(vm_count as usize, 0);
114        reader.read_exact(&mut vms)?;
115        let unk1 = reader.read_u32()?;
116        let mut strings = Vec::with_capacity(string_count as usize);
117        if encoding.is_jis() {
118            let replaces = StrReplacer::new()?;
119            for _ in 0..string_count {
120                let s = reader.read_cstring()?;
121                let s = replaces.replace(s.as_bytes())?;
122                strings.push(decode_to_string(encoding, &s, true)?);
123            }
124        } else {
125            for _ in 0..string_count {
126                let s = reader.read_cstring()?;
127                strings.push(decode_to_string(encoding, s.as_bytes(), true)?);
128            }
129        }
130        let names = match &config.escude_enum_scr {
131            Some(loc) => match load_enum_script(loc, encoding, config) {
132                Ok(list) => {
133                    let mut names = HashMap::new();
134                    let mut vm = VM::new(&vms);
135                    vm.vars.insert(1, 1);
136                    vm.vars.insert(132, 0);
137                    vm.vars.insert(133, 0);
138                    vm.vars.insert(134, 0);
139                    vm.vars.insert(1001, 0);
140                    vm.vars.insert(1003, 0);
141                    for i in 135..140 {
142                        vm.vars.insert(i, 1);
143                    }
144                    let _ = vm.run(Some(Box::new(super::ops::panicon::PaniconOps::new())));
145                    for (index, name) in vm.names.iter() {
146                        if let Some(name) = list.get(*name as usize) {
147                            names.insert(*index as usize, name.text.clone());
148                        }
149                    }
150                    Some(names)
151                }
152                Err(e) => {
153                    eprintln!(
154                        "WARN: Failed to load Escude enum script from {}: {}",
155                        loc, e
156                    );
157                    crate::COUNTER.inc_warning();
158                    None
159                }
160            },
161            None => None,
162        };
163        Ok(EscudeBinScript {
164            vms,
165            unk1,
166            strings,
167            names,
168        })
169    }
170}
171
172impl Script for EscudeBinScript {
173    fn default_output_script_type(&self) -> OutputScriptType {
174        OutputScriptType::Json
175    }
176
177    fn default_format_type(&self) -> FormatOptions {
178        FormatOptions::None
179    }
180
181    fn extract_messages(&self) -> Result<Vec<Message>> {
182        Ok(self
183            .strings
184            .iter()
185            .enumerate()
186            .map(|(i, s)| Message {
187                message: s.replace("<r>", "\n"),
188                name: self.names.as_ref().map(|n| n.get(&i).cloned()).flatten(),
189            })
190            .collect())
191    }
192
193    fn import_messages<'a>(
194        &'a self,
195        messages: Vec<Message>,
196        mut writer: Box<dyn WriteSeek + 'a>,
197        _filename: &str,
198        encoding: Encoding,
199        replacement: Option<&'a ReplacementTable>,
200    ) -> Result<()> {
201        writer.write_all(b"ESCR1_00")?;
202        let mut offsets = Vec::with_capacity(messages.len());
203        let mut strs = Vec::with_capacity(messages.len());
204        let mut len = 0;
205        for message in messages {
206            offsets.push(len);
207            let mut s = message.message.replace("\n", "<r>");
208            if let Some(repl) = replacement {
209                for (from, to) in &repl.map {
210                    s = s.replace(from, to);
211                }
212            }
213            let encoded = encode_string(encoding, &s, false)?;
214            len += encoded.len() as u32 + 1;
215            strs.push(CString::new(encoded)?);
216        }
217        writer.write_u32(offsets.len() as u32)?;
218        offsets.pack(&mut writer, false, encoding)?;
219        writer.write_u32(self.vms.len() as u32)?;
220        writer.write_all(&self.vms)?;
221        writer.write_u32(self.unk1)?;
222        for s in strs {
223            writer.write_all(s.as_bytes_with_nul())?;
224        }
225        Ok(())
226    }
227
228    fn is_archive(&self) -> bool {
229        false
230    }
231}
232
233struct StrReplacer {
234    pub replacements: HashMap<Vec<u8>, Vec<u8>>,
235}
236
237enum JisStr {
238    Single(u8),
239    Double(u8, u8),
240}
241
242impl StrReplacer {
243    pub fn new() -> Result<Self> {
244        let mut s = StrReplacer {
245            replacements: HashMap::new(),
246        };
247        // 0xa0 to 0xde: Half-width katakana in CP932
248        let half_width_katakana = "!? 。「」、…をぁぃぅぇぉゃゅょっーあいうえおかきくけこさしすせそたちつてとなにぬねのはひふへほまみむめもやゆよらりるれろわん゛゜";
249        let mut bytes: Vec<u8> = (0xa0..=0xde).collect();
250        bytes.insert(0, 0x21);
251        bytes.insert(1, 0x3f);
252        s.add(&bytes, half_width_katakana)?;
253        Ok(s)
254    }
255
256    fn add(&mut self, from: &[u8], to: &str) -> Result<()> {
257        let encoding = Encoding::Cp932; // Default encoding, can be changed as needed
258        let tos = UnicodeSegmentation::graphemes(to, true);
259        for (from, to) in from.into_iter().zip(tos) {
260            let from_bytes = vec![from.clone()];
261            let to_bytes = encode_string(encoding, to, true)?;
262            self.replacements.insert(from_bytes, to_bytes);
263        }
264        Ok(())
265    }
266
267    pub fn replace(&self, input: &[u8]) -> Result<Vec<u8>> {
268        let mut result = Vec::new();
269        let mut reader = MemReaderRef::new(input);
270        while let Ok(byte) = reader.read_u8() {
271            if byte < 0x80 || (byte >= 0xa0 && byte <= 0xdf) {
272                result.push(JisStr::Single(byte));
273            } else if (byte >= 0x81 && byte <= 0x9f) || (byte >= 0xe0 && byte <= 0xef) {
274                let next_byte = reader.read_u8()?;
275                if next_byte < 0x40 || next_byte > 0xfc {
276                    return Err(anyhow::anyhow!("Invalid JIS encoding sequence"));
277                }
278                result.push(JisStr::Double(byte, next_byte));
279            } else {
280                return Err(anyhow::anyhow!("Invalid byte in JIS encoding: {}", byte));
281            }
282        }
283        let mut output = Vec::new();
284        for item in result {
285            match item {
286                JisStr::Single(byte) => {
287                    let vec = vec![byte];
288                    if let Some(replacement) = self.replacements.get(&vec) {
289                        output.extend_from_slice(replacement);
290                    } else {
291                        output.push(byte);
292                    }
293                }
294                JisStr::Double(byte1, byte2) => {
295                    let key = vec![byte1, byte2];
296                    if let Some(replacement) = self.replacements.get(&key) {
297                        output.extend_from_slice(replacement);
298                    } else {
299                        output.push(byte1);
300                        output.push(byte2);
301                    }
302                }
303            }
304        }
305        Ok(output)
306    }
307}
308
309#[repr(u8)]
310#[derive(Debug, IntEnum)]
311enum BaseOp {
312    End,
313    Jump,
314    JumpZ,
315    Call,
316    Ret,
317    Push,
318    Pop,
319    Str,
320    SetVar,
321    GetVar,
322    SetFlag,
323    GetFlag,
324    Neg,
325    Add,
326    Sub,
327    Mul,
328    Div,
329    Mod,
330    Not,
331    And,
332    Or,
333    Xor,
334    Shr,
335    Shl,
336    Eq,
337    Ne,
338    Gt,
339    Ge,
340    Lt,
341    Le,
342    LNot,
343    LAnd,
344    LOr,
345    FileLine,
346}
347
348pub(crate) trait ReadParam<T> {
349    fn read_param(&mut self) -> Result<T>;
350}
351
352#[derive(Debug)]
353pub(crate) struct VM<'a, T: std::fmt::Debug> {
354    pub reader: MemReaderRef<'a>,
355    pub data: Vec<T>,
356    pub stack: Vec<u64>,
357    pub strs: Vec<T>,
358    pub vars: HashMap<T, T>,
359    pub flags: HashMap<T, bool>,
360    pub mess: BTreeSet<T>,
361    pub names: HashMap<T, T>,
362}
363
364impl ReadParam<i32> for MemReaderRef<'_> {
365    fn read_param(&mut self) -> Result<i32> {
366        Ok(self.read_i32()?)
367    }
368}
369
370impl<'a, T> VM<'a, T>
371where
372    MemReaderRef<'a>: ReadParam<T>,
373    T: TryInto<u64>
374        + Default
375        + Eq
376        + Ord
377        + Copy
378        + std::fmt::Debug
379        + std::fmt::Display
380        + std::hash::Hash
381        + From<u8>
382        + std::ops::Neg<Output = T>
383        + std::ops::Add<Output = T>
384        + std::ops::Sub<Output = T>
385        + std::ops::Mul<Output = T>
386        + std::ops::Div<Output = T>
387        + std::ops::Rem<Output = T>
388        + std::ops::Not<Output = T>
389        + std::ops::BitAnd<Output = T>
390        + std::ops::BitOr<Output = T>
391        + std::ops::BitXor<Output = T>
392        + std::ops::Shr<Output = T>
393        + std::ops::Shl<Output = T>,
394    anyhow::Error: From<<T as TryInto<u64>>::Error>,
395{
396    pub fn new(data: &'a [u8]) -> Self {
397        VM {
398            reader: MemReaderRef::new(data),
399            data: Vec::new(),
400            stack: Vec::new(),
401            strs: Vec::new(),
402            vars: HashMap::new(),
403            flags: HashMap::new(),
404            mess: BTreeSet::new(),
405            names: HashMap::new(),
406        }
407    }
408
409    pub fn pop_data(&mut self) -> Result<T> {
410        self.data
411            .pop()
412            .ok_or_else(|| anyhow::anyhow!("No data to pop"))
413    }
414
415    fn pop_stack(&mut self) -> Result<u64> {
416        self.stack
417            .pop()
418            .ok_or_else(|| anyhow::anyhow!("No stack to pop"))
419    }
420
421    pub fn run(&mut self, mut custom_ops: Option<Box<dyn CustomOps<T>>>) -> Result<()> {
422        loop {
423            if self.reader.is_eof() {
424                break;
425            }
426            let op = self.reader.read_u8()?;
427            if let Ok(op) = BaseOp::try_from(op) {
428                // println!("Op code: {op:?}");
429                match op {
430                    BaseOp::End => break,
431                    BaseOp::Jump => {
432                        let offset: T = self.reader.read_param()?;
433                        let offset: u64 = offset.try_into()?;
434                        self.reader.seek(SeekFrom::Start(offset))?;
435                    }
436                    BaseOp::JumpZ => {
437                        let offset: T = self.reader.read_param()?;
438                        let offset: u64 = offset.try_into()?;
439                        if self.pop_data()? == Default::default() {
440                            self.reader.seek(SeekFrom::Start(offset))?;
441                        }
442                    }
443                    BaseOp::Call => {
444                        let offset: T = self.reader.read_param()?;
445                        let offset: u64 = offset.try_into()?;
446                        let pos = self.reader.stream_position()?;
447                        self.stack.push(pos);
448                        self.reader.seek(SeekFrom::Start(offset))?;
449                    }
450                    BaseOp::Ret => {
451                        if self.stack.is_empty() {
452                            let code = self.reader.read_u8()?;
453                            if code == 0 && self.reader.is_eof() {
454                                break;
455                            }
456                        }
457                        let stack = self.pop_stack()?;
458                        self.reader.seek(SeekFrom::Start(stack))?;
459                    }
460                    BaseOp::Push => {
461                        let d = self.reader.read_param()?;
462                        self.data.push(d);
463                    }
464                    BaseOp::Pop => {
465                        self.pop_data()?;
466                    }
467                    BaseOp::Str => {
468                        let param = self.reader.read_param()?;
469                        self.strs.push(param);
470                        self.data.push(param);
471                    }
472                    BaseOp::SetVar => {
473                        let value = self.pop_data()?;
474                        let index = self.pop_data()?;
475                        self.vars.insert(index, value);
476                        self.data.push(value);
477                    }
478                    BaseOp::GetVar => {
479                        let index = self.pop_data()?;
480                        let value = self
481                            .vars
482                            .get(&index)
483                            .ok_or_else(|| anyhow::anyhow!("Variable not found: {}", index))?;
484                        self.data.push(*value);
485                    }
486                    BaseOp::SetFlag => {
487                        let value = self.pop_data()?;
488                        let index = self.pop_data()?;
489                        let flag = value != Default::default();
490                        self.flags.insert(index, flag);
491                        self.data.push(value);
492                    }
493                    BaseOp::GetFlag => {
494                        let index = self.pop_data()?;
495                        let flag = self.flags.get(&index).cloned().unwrap_or(false);
496                        self.data
497                            .push(if flag { T::from(1u8) } else { T::from(0u8) });
498                    }
499                    BaseOp::Neg => {
500                        let value = -self.pop_data()?;
501                        self.data.push(value);
502                    }
503                    BaseOp::Add => {
504                        let b = self.pop_data()?;
505                        let a = self.pop_data()?;
506                        self.data.push(a + b);
507                    }
508                    BaseOp::Sub => {
509                        let b = self.pop_data()?;
510                        let a = self.pop_data()?;
511                        self.data.push(a - b);
512                    }
513                    BaseOp::Mul => {
514                        let b = self.pop_data()?;
515                        let a = self.pop_data()?;
516                        self.data.push(a * b);
517                    }
518                    BaseOp::Div => {
519                        let b = self.pop_data()?;
520                        if b == Default::default() {
521                            return Err(anyhow::anyhow!("Division by zero"));
522                        }
523                        let a = self.pop_data()?;
524                        self.data.push(a / b);
525                    }
526                    BaseOp::Mod => {
527                        let b = self.pop_data()?;
528                        if b == Default::default() {
529                            return Err(anyhow::anyhow!("Division by zero"));
530                        }
531                        let a = self.pop_data()?;
532                        self.data.push(a % b);
533                    }
534                    BaseOp::Not => {
535                        let value = self.pop_data()?;
536                        self.data.push(!value);
537                    }
538                    BaseOp::And => {
539                        let b = self.pop_data()?;
540                        let a = self.pop_data()?;
541                        self.data.push(a & b);
542                    }
543                    BaseOp::Or => {
544                        let b = self.pop_data()?;
545                        let a = self.pop_data()?;
546                        self.data.push(a | b);
547                    }
548                    BaseOp::Xor => {
549                        let b = self.pop_data()?;
550                        let a = self.pop_data()?;
551                        self.data.push(a ^ b);
552                    }
553                    BaseOp::Shr => {
554                        let b = self.pop_data()?;
555                        let a = self.pop_data()?;
556                        self.data.push(a >> b);
557                    }
558                    BaseOp::Shl => {
559                        let b = self.pop_data()?;
560                        let a = self.pop_data()?;
561                        self.data.push(a << b);
562                    }
563                    BaseOp::Eq => {
564                        let b = self.pop_data()?;
565                        let a = self.pop_data()?;
566                        self.data
567                            .push(if a == b { T::from(1u8) } else { T::from(0u8) });
568                    }
569                    BaseOp::Ne => {
570                        let b = self.pop_data()?;
571                        let a = self.pop_data()?;
572                        self.data
573                            .push(if a != b { T::from(1u8) } else { T::from(0u8) });
574                    }
575                    // Original code may contains undefined behavior for these operations
576                    BaseOp::Gt => {
577                        let a = self.pop_data()?;
578                        let b = self.pop_data()?;
579                        self.data
580                            .push(if a > b { T::from(1u8) } else { T::from(0u8) });
581                    }
582                    BaseOp::Ge => {
583                        let a = self.pop_data()?;
584                        let b = self.pop_data()?;
585                        self.data
586                            .push(if a >= b { T::from(1u8) } else { T::from(0u8) });
587                    }
588                    BaseOp::Lt => {
589                        let a = self.pop_data()?;
590                        let b = self.pop_data()?;
591                        self.data
592                            .push(if a < b { T::from(1u8) } else { T::from(0u8) });
593                    }
594                    BaseOp::Le => {
595                        let a = self.pop_data()?;
596                        let b = self.pop_data()?;
597                        self.data
598                            .push(if a <= b { T::from(1u8) } else { T::from(0u8) });
599                    }
600                    BaseOp::LNot => {
601                        let value = self.pop_data()?;
602                        self.data.push(if value == Default::default() {
603                            T::from(1u8)
604                        } else {
605                            T::from(0u8)
606                        });
607                    }
608                    BaseOp::LAnd => {
609                        let b = self.pop_data()? != Default::default();
610                        let a = self.pop_data()? != Default::default();
611                        self.data
612                            .push(if a && b { T::from(1u8) } else { T::from(0u8) });
613                    }
614                    BaseOp::LOr => {
615                        let b = self.pop_data()? != Default::default();
616                        let a = self.pop_data()? != Default::default();
617                        self.data
618                            .push(if a || b { T::from(1u8) } else { T::from(0u8) });
619                    }
620                    BaseOp::FileLine => {
621                        let _: T = self.reader.read_param()?;
622                    }
623                }
624                continue;
625            }
626            if let Some(ops) = &mut custom_ops {
627                let nbreak = ops.run(self, op)?;
628                if nbreak {
629                    break;
630                }
631            } else {
632                return Err(anyhow::anyhow!("Unknown operation: {}", op));
633            }
634        }
635        Ok(())
636    }
637
638    pub fn skip_n_params(&mut self, n: u64, nbreak: bool) -> Result<bool> {
639        for _ in 0..n {
640            self.pop_data()?;
641        }
642        Ok(nbreak)
643    }
644
645    pub fn skip_params(&mut self, nbreak: bool) -> Result<bool> {
646        let count: T = self.reader.read_param()?;
647        let count: u64 = count.try_into()?;
648        self.skip_n_params(count, nbreak)
649    }
650
651    pub fn read_params(&mut self, ncount: Option<u64>) -> Result<Vec<T>> {
652        let count = match ncount {
653            Some(count) => count,
654            None => {
655                let count: T = self.reader.read_param()?;
656                count.try_into()?
657            }
658        };
659        let data_len = self.data.len();
660        if (data_len as u64) < count {
661            return Err(anyhow::anyhow!(
662                "Not enough data to read {} parameters, only {} parameters available",
663                count,
664                data_len
665            ));
666        }
667        let mut params = Vec::with_capacity(count as usize);
668        params.resize(count as usize, Default::default());
669        params.copy_from_slice(&self.data[data_len - count as usize..]);
670        self.data.truncate(data_len - count as usize);
671        Ok(params)
672    }
673}